namespace cxxcall
{

bool cb_data::_Reg_struct_ret ()
{
  switch (this->rsize)
    {
      case 1: case 2: case 4:
        break;
      case 8:
        {
          auto flg = this->flags &
            (msvc_struct_ret | gcc_struct_ret | split_struct_ret);
          if ((flg & msvc_struct_ret) != 0 ||
              flg == (gcc_struct_ret | split_struct_ret))
            break;
          
          this->raddr = *(void **)this->curr;
          this->curr += sizeof (uintptr_t);
          return (false);
        }
    }

  return (true);
}

void* cb_data::xarg (size_t size, size_t align, bool integral, bool)
{
  if (!integral)
    {
      auto als = cb_data::struct_alignment (align);
      this->curr = (this->curr + als - 1) & -(intptr_t)als;
    }

  void *ret = (void *)this->curr;
  this->curr += cb_data::arg_size (size);
  return (ret);
}

long long cb_data::arg_ll ()
{
  return (*(long long *)this->xarg (sizeof (long long),
                                    alignof (long long), true, true));
}

float cb_data::arg_f ()
{
  return (*(float *)this->xarg (sizeof (float),
                                alignof (float), true, true));
}

double cb_data::arg_d ()
{
  return (*(double *)this->xarg (sizeof (double),
                                 alignof (double), true, true));
}

#ifndef CXXCALL_LONG_DOUBLE_ALIASED

long double cb_data::arg_ld ()
{
  return (*(long double*)this->xarg (sizeof (long double),
                                     alignof (long double), true, true));
}

#endif

}
